﻿using EBA.Data;
using EBA.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Text;
using EBA.Helpers;
using System.Linq.Expressions;

namespace EBA.Logging
{
    /// <summary>
    /// Write and read the diagnostic message in a xml file.
    /// </summary>
    [Export("XmlFileLogProvider", typeof(ILogProvider))]
    public class XmlFileLogProvider : ILogProvider
    {
        static volatile object SycnRoot = new object();

        string LogFile { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public XmlFileLogProvider()
        {
            this.Init();
        }


        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ILogger GetLogger(string name = null)
        {
            return new XmlFileLogger(this.LogFile, name);
        }

        /// <summary>
        /// 获取logs
        /// </summary>
        public IQuery<ILog> Logs
        {
            get
            {
                return new XmlFileLogQuery(this.LogFile);
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        public void Delete(string id)
        {
            var temptfile = Path.Combine(AppRuntime.ApplicationPath, "logs_delete.xml");
            lock (SycnRoot)
            {
                using (var writer = File.CreateText(temptfile))
                {
                    using (var stream = File.OpenRead(this.LogFile))
                    {
                        using (var reader = new StreamReader(stream))
                        {
                            while (reader.Peek() > -1)
                            {
                                var str = reader.ReadLine();
                                var element = XmlFileLogSerializer.Deserialize(str);
                                if (element.Id != id)
                                {
                                    writer.WriteLine(str);
                                }
                            }
                        }
                    }
                }
                File.Delete(this.LogFile);
                File.Move(temptfile, this.LogFile);
            }
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="filterExpression"></param>
        public void DeleteAll(Expression<Func<ILog, bool>> filterExpression)
        {
            var temptfile = Path.Combine(AppRuntime.ApplicationPath, "logs_delete.xml");
            lock (SycnRoot)
            {
                var logs = Logs.AsQuerybale.Where(filterExpression);
                using (var writer = File.Open(temptfile, FileMode.Append))
                {
                    using (var stream = File.OpenRead(this.LogFile))
                    {
                        using (var reader = new StreamReader(stream))
                        {
                            while (reader.Peek() > -1)
                            {
                                var str = reader.ReadLine();
                                var log = XmlFileLogSerializer.Deserialize(str);
                                if (logs.Where(i => i.Id == log.Id).Count() == 0)
                                {
                                    var sb = new StringBuilder(str);
                                    sb.AppendLine();
                                    var buffer = UTF8Encoding.UTF8.GetBytes(sb.ToString());
                                    writer.Write(buffer, 0, buffer.Length);
                                }
                            }
                        }
                    }
                }
            }
            File.Delete(this.LogFile);
            File.Move(temptfile, this.LogFile);
        }


        private void Init()
        {
            this.LogFile = Path.Combine(AppRuntime.ApplicationPath, "logs.xml");
            CreateEmptyXmlFile(this.LogFile);
        }

        private void CreateEmptyXmlFile(string path)
        {
            if (File.Exists(this.LogFile) == false)
            {
                //create a empty log file
                using (var writer = File.CreateText(path))
                {

                }
            }
        }
    }
}
